/**
 * @author Jun
 * on Jul 2, 2012, 2012
 */
package com.fastwire.carriere.rad.controller;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

import com.fastwire.carriere.common.Messages;
import com.fastwire.carriere.common.constant.AppConstants;
import com.fastwire.carriere.common.exception.ResourceException;
import com.fastwire.carriere.common.util.CommonLogger;
import com.fastwire.carriere.dao.DAOException;
import com.fastwire.carriere.dao.DAOFactory;
import com.fastwire.carriere.dao.DiscoveryRecordDao;
import com.fastwire.carriere.discovery.entity.DiscoveryRecord;
import com.fastwire.carriere.rad.dao.RadDao;
import com.fastwire.carriere.rad.entity.Rad;
import com.fastwire.carriere.rad.snmpadapter.SnmpAdapter;
import com.fastwire.carriere.rad.util.NetworkUtil;

/**
 * @author Jun
 * on Jul 2, 2012, 2012
 */
public class RadDiscoveryImp implements RadDiscovery
{
    private final DiscoveryRecordDao discoveryRecordDao = DAOFactory.getInstance()
            .getDiscoveryRecordDao();
    
    private final RadDao raddao = DAOFactory.getInstance().getRadDao();

    // the format of a ipSubnet shuld be like: 192.168.10.0/24
    // if only 192.168.10.0, it's only one address
    @Override
    public String doConccrentDiscovery(List<String> ipSubnetList) throws DAOException,
            ResourceException
    {
        DiscoveryRecord discoveryRecord = precheckDiscovery(AppConstants.DISCOVERY_RAD_FULL);

        CommonLogger.info(this, "done precheck");
        List<String> allIPs = null;

        for (String ipSubnet : ipSubnetList)
        {
            // for every ipsubnet, create a thread;
            CommonLogger.info(this, "for ip/subnet: " + ipSubnet);

            allIPs = NetworkUtil.getAllIPsBySubnet(ipSubnet);
        }
        
        if(null==allIPs || allIPs.size()<=0)
        {
            return "No IP is specified.";
        }
        
        try
        {
            RadConcurrentDiscovery radDisc = new RadConcurrentDiscovery();
            radDisc.discovery(allIPs);

            List<Callable<List<Rad>>> callables = radDisc.getCallable();

            if (!callables.isEmpty())
            {
                ExecutorService executor = Executors.newFixedThreadPool(callables.size());
                List<Future<List<Rad>>> futures = executor.invokeAll(callables);
                
                if (!executor.isShutdown())
                {
                    executor.shutdown();
                }
                
                while (!executor.isTerminated())
                {
                    executor.awaitTermination(1, TimeUnit.MINUTES);
                }
                List<Rad> radList = new ArrayList<Rad>();

                for (Future<List<Rad>> future : futures)
                {
                    radList.addAll(future.get());
                }
                
                CommonLogger.info(this, "Total rad:" + radList.size());

                raddao.saveOrUpdate(radList);
            }

            discoveryRecord.handleComplete();
        }
        catch (Throwable e)
        {
            e.printStackTrace();
            CommonLogger.error(this, e.getMessage());
            discoveryRecord.handleException(e.getMessage());
        }
        finally
        {
            discoveryRecordDao.saveOrUpdate(discoveryRecord);
        }

        return null;
    }

    
    @Override
    public String adhocDiscovery(String ip) throws DAOException
    {
        Rad rad = null;
        try
        {
            rad = raddao.getRadByIP(ip);
            if (null != rad)
            {
                raddao.invalidate(rad);
            }

            rad = new Rad(ip);

            SnmpAdapter snmpAdp = new SnmpAdapter();
            snmpAdp.getRadInfo(rad);

            raddao.saveOrUpdate(rad);
        }
        catch (DAOException e)
        {
            e.printStackTrace();
        }

        return null;
    }

    //
    private synchronized DiscoveryRecord precheckDiscovery(String type) throws DAOException,
            ResourceException
    {
        List<DiscoveryRecord> radDiscovery = discoveryRecordDao.findRadDiscovery();

        if (null != radDiscovery && !radDiscovery.isEmpty())
        {
            throw new ResourceException(
                    Messages.getString("message.discovery.discoverywip.exception"));
        }

        DiscoveryRecord discoveryRecord = new DiscoveryRecord();
        discoveryRecord.handleRadSetup(type);
        discoveryRecordDao.saveOrUpdate(discoveryRecord);

        return discoveryRecord;
    }
    
}
